package com.log4jviewer.ui.preferences.filters;

import java.util.List;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.log4jviewer.Activator;
import com.log4jviewer.filters.FilterModel;

/**
 * Class represents a part of filters preferences page. It is responsible for building a table, where filters are
 * displayed, and control buttons: Add and Remove to add/remove filters.
 * 
 * @author <a href="mailto:rd.ryly@gmail.com">Ruslan Diachenko</a></br> <a
 *         href="mailto:Daniil.Yaroslavtsev@gmail.com">Daniil Yaroslavtsev</a>
 */
public class FilterSettings extends AbstractFilterSettings {

    public static final int COLUMN_COUNT = 3;

    public static final int ENABLE_COLUMN_INDEX = 2;

    private static final Image CHECKED = Activator.getImageDescriptor(
            "icons/radio_checked.gif").createImage();

    private static final Image UNCHECKED = Activator.getImageDescriptor(
            "icons/radio_unchecked.gif").createImage();

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private TableViewer tableViewer;

    private FilterController filterController;

    private FilterContentProvider filterContentProvider;

    private Button addNewFilterButton;

    private Button removeFilterButton;

    private Table filterTable;

    public FilterSettings(final FilterController filterController,
            final FilterContentProvider filterContentProvider) {
        this.filterController = filterController;
        this.filterContentProvider = filterContentProvider;
    }

    @Override
    public TableViewer getTableViewer() {
        return tableViewer;
    }

    @Override
    protected void createTableViewer(final Composite composite) {
        tableViewer = new TableViewer(composite, SWT.SINGLE
                | SWT.H_SCROLL
                | SWT.V_SCROLL
                | SWT.BORDER
                | SWT.FULL_SELECTION);

        tableViewer.setUseHashlookup(true);
        tableViewer.setContentProvider(new ArrayContentProvider());

        filterTable = tableViewer.getTable();
        filterTable.setHeaderVisible(true);
        filterTable.setLinesVisible(true);
        GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 17);
        filterTable.setLayoutData(gridData);

        createColumns();

        tableViewer.setInput(filterContentProvider.getFilters());
        filterController.addFilterTableListener(tableViewer, filterContentProvider);
        filterController.setCellEditingStrategy(tableViewer);

        Listener paintListener = new Listener() {
            @Override
            public void handleEvent(final Event event) {
                if ((event.type == SWT.PaintItem) && (event.index == ENABLE_COLUMN_INDEX)) {
                    TableItem item = (TableItem) event.item;
                    Image radioBtnImg = getImage(item.getData());

                    Rectangle imageBounds = radioBtnImg.getBounds();

                    int xOffset = (filterTable.getColumn(ENABLE_COLUMN_INDEX).getWidth() - imageBounds.width) / 2;
                    int yOffset = (item.getBounds().height - imageBounds.height) / 2;

                    event.gc.drawImage(radioBtnImg, event.x + xOffset, event.y + yOffset);
                }
            }
        };

        filterTable.addListener(SWT.PaintItem, paintListener);

        filterTable.addKeyListener(new KeyListener() {

            @Override
            public void keyReleased(final KeyEvent e) {
            }

            @Override
            public void keyPressed(final KeyEvent e) {

                System.out.println(e.keyCode);
                switch (e.keyCode) {
                case SWT.INSERT:
                    doAddNewFilterButtonAction();
                    break;
                case SWT.DEL:
                    doRemoveFilterButtonAction();
                    break;
                default:
                    break;
                }
            }
        });

        tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(final SelectionChangedEvent evt) {
                checkAndSetRemoveBtnState();
                int activeFilterIndex = filterTable.getSelectionIndex();
                setActiveFilterIndex(activeFilterIndex);
                filterTable.redraw();
            }
        });

        // Selects a full row even when any it`s cell is editing
        filterTable.addListener(SWT.EraseItem, new Listener() {
            @Override
            public void handleEvent(final Event event) {
                if (!tableViewer.getSelection().isEmpty()) {
                    TableItem eventItem = (TableItem) event.item;

                    FilterModel filterModel = (FilterModel) eventItem.getData();
                    if (isFilterActive(filterModel)) {
                        event.detail |= SWT.SELECTED;
                    }
                }
            }
        });

    }

    @Override
    protected void createColumns() {
        final String nameColumnTitle = "Name";
        final int nameColumnWidth = 100;
        TableViewerColumn nameColumn = createSingleColumn(tableViewer, nameColumnTitle,
                nameColumnWidth);
        nameColumn.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(final Object element) {
                FilterModel filterModel = (FilterModel) element;
                String filterName = filterModel.getFilterName();
                logger.debug("New filter name: {}", filterName);
                return filterName;
            }
        });
        nameColumn.setEditingSupport(new FilterNameCellEditor(tableViewer));

        final String descriptionColumnTitle = "Description";
        final int descriptionColumnWidth = 300;
        TableViewerColumn desriptionColumn = createSingleColumn(tableViewer,
                descriptionColumnTitle,
                descriptionColumnWidth);
        desriptionColumn.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(final Object element) {
                FilterModel filterModel = (FilterModel) element;
                String filterDescription = filterModel.getFilterDescr();
                logger.debug("Filter description: {}", filterDescription);
                return filterDescription;
            }
        });
        desriptionColumn.setEditingSupport(new FilterDescriptionCellEditor(tableViewer));

        final String enableColumnTitle = "Enable";
        final int enableColumnWidth = 50;
        TableViewerColumn enableColumn = createSingleColumn(tableViewer, enableColumnTitle,
                enableColumnWidth);
        enableColumn.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(final Object element) {
                return null;
            }
        });

    }

    public Image getImage(final Object element) {
        Image currentImage;

        if (isFilterActive((FilterModel) element)) {
            currentImage = CHECKED;
        } else {
            currentImage = UNCHECKED;
        }
        return currentImage;
    }

    public boolean isFilterActive(final FilterModel filterModel) {
        return filterContentProvider.isFilterActive(filterModel);
    }

    public int getFilterIndex(final FilterModel filterModel) {
        List<FilterModel> filterModels = filterContentProvider.getFilters();
        return filterModels.indexOf(filterModel);
    }

    public void setActiveFilterIndex(final int activeFilterIndex) {
        filterContentProvider.setActiveFilterIndex(activeFilterIndex);
    }

    @Override
    protected void createButtons(final Composite composite) {
        addNewFilterButton = createSingleButton(composite, ADD_BUTTON_NAME);
        removeFilterButton = createSingleButton(composite, REMOVE_BUTTON_NAME);

        checkAndSetRemoveBtnState();

        addNewFilterButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
                doAddNewFilterButtonAction();
            }
        });

        removeFilterButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
                doRemoveFilterButtonAction();
            }
        });
    }

    public void setActiveFilterSelection() {
        // Programmatically selecting active filter in filters table. Selection events will be fired manually in 
        // FilterPreferencePage.fireFilterTableSelectionEvents() when all tables and buttons on page will be composed.
        if (!filterContentProvider.isFilterListEmpty()) {
            int activeFilterIndex = filterContentProvider.getActiveFilterIndex();
            setActiveFilterIndex(activeFilterIndex);
            filterTable.setSelection(activeFilterIndex);
        }
    }

    private void doAddNewFilterButtonAction() {
        FilterModel filterModel = filterContentProvider.createFilter();
        tableViewer.add(filterModel);
    }

    private void doRemoveFilterButtonAction() {

        int selectedFilterIndex = filterTable.getSelectionIndex();

        if (selectedFilterIndex >= 0) {
            filterContentProvider.removeFilter(selectedFilterIndex);
            filterTable.remove(selectedFilterIndex);
            filterController.removeItemsFromFilterRuleTable();
        }

        selectFirstFilter();
        checkAndSetRemoveBtnState();
    }

    private void selectFirstFilter() {
        if (!filterContentProvider.isFilterListEmpty()) {
            int activeFilterIndex = 0;
            setActiveFilterIndex(activeFilterIndex);
            filterTable.setSelection(activeFilterIndex);
        }
    }

    public void checkAndSetRemoveBtnState() {
        boolean isTableSelectionEmpty = tableViewer.getSelection().isEmpty();
        removeFilterButton.setEnabled(!isTableSelectionEmpty);
    }
}
